﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Input.Touch;


namespace G.XNA.Component
{
    /// <summary>
    /// 这是一个实现 IUpdateable 的游戏组件。
    /// </summary>
    public class DrawingBoard : DrawableGameComponent, IProcessTouch
    {
        SpriteBatch spriteBatch;
        Texture2D canvas;
        int? touchId = null;
        uint[] pixels;
        List<float> xCollection = new List<float>();
        public DrawingBoard(Game game)
            : base(game)
        {
            // TODO: 在此处构造任何子组件
        }

        public Color DrawingColor { get; set; }

        private Vector2 size;
        /// <summary>
        /// 相对于屏幕的尺寸
        /// </summary>
        public Vector2 Size
        {
            get
            {
                return size;
            }
            set
            {
                if (size != value)
                {
                    size = value;
                    CreateCanvas();
                }
            }
        }
        private Rectangle destination;
        /// <summary>
        /// 相对于屏幕的位置和尺寸
        /// </summary>
        public Rectangle Destination
        {
            get
            {
                return destination;
            }
            set
            {
                destination = value;
                position = new Vector2(destination.X, destination.Y);
            }
        }
        private Vector2 position;
        private bool canvasNeedsUpdate;
        /// <summary>
        /// 允许游戏组件在开始运行之前执行其所需的任何初始化。
        /// 游戏组件能够在此时查询任何所需服务和加载内容。
        /// </summary>
        public override void Initialize()
        {
            // TODO: 在此处添加初始化代码
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(this.GraphicsDevice);
            base.LoadContent();
        }

        private void CreateCanvas()
        {
            this.canvas = new Texture2D(spriteBatch.GraphicsDevice, (int)Size.X, (int)Size.Y);
            pixels = new uint[canvas.Width * canvas.Height];
            canvas.GetData<uint>(pixels);
            ClearPixel();
        }

        public void ClearPixel()
        {
            for (int y = 0; y < canvas.Height; y++)
            {
                for (int x = 0; x < canvas.Width; x++)
                {
                    pixels[x + canvas.Width * y] = Color.GhostWhite.PackedValue;
                }
            }
            canvas.SetData<uint>(pixels);
        }

        /// <summary>
        /// 允许游戏组件进行自我更新。
        /// </summary>
        /// <param name="gameTime">提供计时值的快照。</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: 在此处添加更新代码
            base.Update(gameTime);
        }

        public void BenginProcess()
        {
            canvasNeedsUpdate = false;
        }


        public bool ProcessTouch(Microsoft.Xna.Framework.Input.Touch.TouchLocation touch)
        {
            bool touchHandled = false;
            bool isInside = Destination.Contains((int)touch.Position.X,
                                                 (int)touch.Position.Y);
            switch (touch.State)
            {
                case TouchLocationState.Pressed:
                    if (isInside)
                    {
                        touchId = touch.Id;
                        touchHandled = true;
                    }
                    break;

                case TouchLocationState.Moved:
                    if (touchId.HasValue && touchId.Value == touch.Id)
                    {
                        TouchLocation prevTouchLocation;
                        touch.TryGetPreviousLocation(out prevTouchLocation);

                        Vector2 point1 = prevTouchLocation.Position - position;
                        Vector2 point2 = touch.Position - position;

                        float radius = 12;
                        RoundCappedLine line = new RoundCappedLine(point1, point2, radius);

                        int yMin = (int)(Math.Min(point1.Y, point2.Y) - radius);
                        int yMax = (int)(Math.Max(point1.Y, point2.Y) + radius);

                        yMin = Math.Max(0, Math.Min(canvas.Height, yMin));
                        yMax = Math.Max(0, Math.Min(canvas.Height, yMax));

                        for (int y = yMin; y < yMax; y++)
                        {
                            xCollection.Clear();
                            line.GetAllX(y, xCollection);

                            if (xCollection.Count == 2)
                            {
                                int xMin = (int)(Math.Min(xCollection[0], xCollection[1]) + 0.5f);
                                int xMax = (int)(Math.Max(xCollection[0], xCollection[1]) + 0.5f);

                                xMin = Math.Max(0, Math.Min(canvas.Width, xMin));
                                xMax = Math.Max(0, Math.Min(canvas.Width, xMax));

                                for (int x = xMin; x < xMax; x++)
                                {
                                    pixels[y * canvas.Width + x] = DrawingColor.PackedValue;
                                }
                                canvasNeedsUpdate = true;
                            }
                        }
                        touchHandled = true;
                    }
                    break;

                case TouchLocationState.Released:
                    if (touchId.HasValue && touchId.Value == touch.Id)
                    {
                        touchId = null;
                        touchHandled = true;
                    }
                    break;
            }
            return touchHandled;
        }

        public void EndProcess()
        {
            GraphicsDevice.Textures[0] = null;
            if (canvasNeedsUpdate)
                canvas.SetData<uint>(pixels);
        }

        public override void Draw(GameTime gameTime)
        {
            spriteBatch.Begin();
            spriteBatch.Draw(canvas, position, Color.White);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}
